<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Effects</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Java2D, Java, tutorial, effects, programming, Graphics, multiplatform">
<meta name="description" content="In this part of the Java 2D tutorial, we perform some effects.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>


<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">

<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Effects</h1>


<p>
In this part of the Java 2D programming tutorial, we will show some effects. 
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* top_horizontal */
google_ad_slot = "3327173442";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<h2>Bubbles</h2>

<p>
In the first example, we will see growing coloured bubbles, that randomly
appear and disappear on the screen. The example comes from the Java 2D demo.  
</p>

<div class="codehead">Bubbles.java</div>
<pre class="code">
package com.zetcode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Bubbles extends JPanel implements ActionListener {


    private static Color colors[] = { 
      Color.blue, Color.cyan, Color.green, 
      Color.magenta, Color.orange, Color.pink, 
      Color.red, Color.yellow, Color.lightGray, Color.white
    };


    private Ellipse2D.Float[] ellipses;
    private double esize[];
    private float estroke[];
    private double maxSize = 0;
    private boolean initialize = true;

    Timer timer;
    ActionListener updateProBar;


    public Bubbles() {

        setBackground(Color.black);
        ellipses = new Ellipse2D.Float[25];
        esize = new double[ellipses.length];
        estroke = new float[ellipses.length];

        for (int i = 0; i &lt; ellipses.length; i++) {
            ellipses[i] = new Ellipse2D.Float();
            getRandomXY(i, 20 * Math.random(), 200, 200);
        }

        timer = new Timer(20, this);
        timer.setInitialDelay(190);
        timer.start();
    }


    public void getRandomXY(int i, double size, int w, int h) {

        esize[i] = size;
        estroke[i] = 1.0f;
        double x = Math.random() * (w - (maxSize / 2));
        double y = Math.random() * (h - (maxSize / 2));
        ellipses[i].setFrame(x, y, size, size);
    }


    public void reset(int w, int h) {

        maxSize = w / 10;
        for (int i = 0; i &lt; ellipses.length; i++) {
            getRandomXY(i, maxSize * Math.random(), w, h);
        }
    }


    public void step(int w, int h) {

        for (int i = 0; i &lt; ellipses.length; i++) {

            estroke[i] += 0.025f;
            esize[i]++;

            if (esize[i] > maxSize) {
                getRandomXY(i, 1, w, h);

            } else {
                ellipses[i].setFrame(ellipses[i].getX(), ellipses[i].getY(),
                                     esize[i], esize[i]);
            }
        }
    }


    public void render(int w, int h, Graphics2D g2) {

        for (int i = 0; i &lt; ellipses.length; i++) {
            g2.setColor(colors[i % colors.length]);
            g2.setStroke(new BasicStroke(estroke[i]));
            g2.draw(ellipses[i]);
        }
    }


    public void paint(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g;

        RenderingHints rh =
            new RenderingHints(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);

        rh.put(RenderingHints.KEY_RENDERING,
               RenderingHints.VALUE_RENDER_QUALITY);

        g2.setRenderingHints(rh);
        Dimension size = getSize();

        if (initialize) {
            reset(size.width, size.height);
            initialize = false;
        }

        this.step(size.width, size.height);

        render(size.width, size.height, g2);

    }


    public void actionPerformed(ActionEvent e) {
        repaint();
    }

    public static void main(String[] args) {

        JFrame frame = new JFrame("Bubbles");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new Bubbles());
        frame.setSize(350, 250);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
</pre>

<p>
This is bubbles example.
</p>


<pre class="explanation">
private static Color colors[] = { 
   Color.blue, Color.cyan, Color.green, 
   Color.magenta, Color.orange, Color.pink, 
   Color.red, Color.yellow, Color.lightGray, Color.white
};
</pre>

<p>
These are the colors of the bubbles. 
</p>


<pre class="explanation">
esize = new double[ellipses.length];
estroke = new float[ellipses.length];
</pre>

<p>
These are size and stroke arrays. Both size and stroke of 
the bubble grow during the animation.
</p>

<pre class="explanation">
esize[i] = size;
estroke[i] = 1.0f;
double x = Math.random() * (w - (maxSize / 2));
double y = Math.random() * (h - (maxSize / 2));
ellipses[i].setFrame(x, y, size, size);
</pre> 

<p>
In the <code>getRandomXY()</code> method, we set the default size and 
stroke and set a random position for the bubble. 
</p>

<pre class="explanation">
estroke[i] += 0.025f;
esize[i]++;
</pre> 

<p>
In every animation step, the stroke and the size of the bubble grows. 
</p>


<pre class="explanation">
if (esize[i] > maxSize) {
    getRandomXY(i, 1, w, h);

} else {
    ellipses[i].setFrame(ellipses[i].getX(), ellipses[i].getY(),
                    esize[i], esize[i]);
}
</pre> 

<p>
After the bubble reaches its maximum size, it is reset to the 
minimum size and randomly repositioned
on the panel. Else it is displayed as it is. 
</p>

<img src="/img/gfx/java2d/bubbles.png" alt="Bubbles">
<div class="figure">Figure: Bubbles</div>


<h2>Star</h2>

<p>
The next example shows a rotating and scaling star. 
</p>

<div class="codehead">Star.java</div>
<pre class="code">
package com.zetcode;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Star extends JPanel implements ActionListener {

    double points[][] = { 
        { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, 
        { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, 
        { 40, 190 }, { 50, 125 }, { 0, 85 } 
    };

    Timer timer;

    private double angle = 0;
    private double scale = 1;
    private double delta = 0.01;

    public Star() {

        timer = new Timer(10, this);
        timer.start();
    }

    public void paint(Graphics g) {
        super.paint(g);

        int h = getHeight();
        int w = getWidth();


        Graphics2D g2d = (Graphics2D)g;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                             RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                             RenderingHints.VALUE_RENDER_QUALITY);

        g2d.translate(w/2, h/2);
        GeneralPath star = new GeneralPath();
        star.moveTo(points[0][0], points[0][1]);

        for (int k = 1; k &lt; points.length; k++)
            star.lineTo(points[k][0], points[k][1]);

        star.closePath();
        g2d.rotate(angle);
        g2d.scale(scale, scale);

        g2d.fill(star);
    }

    public static void main(String[] args) {

        JFrame frame = new JFrame("Moving star");
        frame.add(new Star());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(420, 250);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }


    public void actionPerformed(ActionEvent e) {

        if ( scale &lt; 0.01 ) {
            delta = -delta;
        } else if (scale > 0.99) {
            delta = -delta;
        }

        scale += delta;
        angle += 0.01;

        repaint();  
    }
}
</pre>

<p>
In this demo, we have a star. The star rotates and grows and then shrinks. Quite a nice demo.
</p>


<pre class="explanation">
double points[][] = { 
    { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, 
    { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, 
    { 40, 190 }, { 50, 125 }, { 0, 85 } 
};
</pre> 

<p>
 These points are used to draw the star. 
</p>

<pre class="explanation">
private double angle = 0;
private double scale = 1;
private double delta = 0.01;
</pre> 

<p>
The angle is used when we rotate the star. The scale factor determines 
the size of the star. Finally, the delta factor
is the amount of the change of the scale.
</p>

<pre class="explanation">
if ( scale &lt; 0.01 ) {
    delta = -delta;
} else if (scale > 0.99) {
    delta = -delta;
}
</pre> 

<p>
Here the star stops shrinking and starts growing and vice versa. 
</p>


<h2>Puff</h2>

<p>
Next we show a puff effect. 
</p>

<div class="codehead">Star.java</div>
<pre class="code">
package com.zetcode;
 
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Puff extends JPanel implements ActionListener {

    Timer timer;
    int x = 1;
    float alpha = 1;

    public Puff() {
        timer = new Timer(8, this);
        timer.setInitialDelay(190);
        timer.start();
    }

    public void paint(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;

        RenderingHints rh =
            new RenderingHints(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        rh.put(RenderingHints.KEY_RENDERING,
               RenderingHints.VALUE_RENDER_QUALITY);

        g2d.setRenderingHints(rh);

        Font font = new Font("Dialog", Font.PLAIN, x);
        g2d.setFont(font);

        FontMetrics fm = g2d.getFontMetrics();
        String s = "ZetCode";
        Dimension size = getSize();

        int w = (int) size.getWidth();
        int h = (int) size.getHeight();

        int stringWidth = fm.stringWidth(s);

        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
             alpha));

        g2d.drawString(s, (w - stringWidth) / 2, h / 2);
    }


    public static void main(String[] args) {

        JFrame frame = new JFrame("Puff");
        frame.add(new Puff());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        x += 1;

        if (x > 40)
            alpha -= 0.01;

        if (alpha &lt;= 0.01)
            timer.stop();
        repaint();
    }
}
</pre>

<p>
This effect is common in flash animations or film intros. Text grows 
gradually on the screen and after some time
it slowly disappears. 
</p>

<pre class="explanation">
Font font = new Font("Dialog", Font.PLAIN, x);
g2d.setFont(font);
</pre> 

<p>
This is the font that we use for our text. 
</p>

<pre class="explanation">
FontMetrics fm = g2d.getFontMetrics();
</pre> 

<p>
Here we get the <code>FontMetrics</code> class. The class 
stores information about the rendering of a particular font on a particular screen. 
</p>

<pre class="explanation">
int stringWidth = fm.stringWidth(s);
</pre> 

<p>
We use the <code>stringWidth()</code> method of the 
<code>FontMetrics</code> object to get the width
of our screen. We need it in order to place the text in the 
middle of the screen. 
</p>

<pre class="explanation">
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
</pre> 

<p>
Here we set the transparency of the text being drawn. 
</p>

<pre class="explanation">
g2d.drawString(s, (w - stringWidth) / 2, h / 2);
</pre> 

<p>
This code line draws the string in the (horizontal) middle of the screen. 
</p>

<pre class="explanation">
if (x > 40)
    alpha -= 0.01;
</pre> 

<p>
After the string is 40 pixels big, it begins fading. 
</p>

<p>
In this part of the Java 2D tutorial, we did some visual effects.
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified November 2, 2008  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

